package cc.zzone.client;

import cc.zzone.bean.ChatWebsocketServer;
import cc.zzone.domain.Draft_6455;
import io.netty.channel.group.ChannelGroup;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;

import java.net.URI;
import java.util.Map;

/**
 * 弹幕服务监听器公共对象
 *
 * @author jinzhengze
 * @since 2023年10月20日
 */
@Slf4j
public abstract class MyWsClient extends WebSocketClient {

    private final String key; // 监听器key platform:room
    private Thread heartBeatThread = null; // 心跳线程
    private final ChannelGroup channelGroup; // 当前连接的所有客户端channel
    private int reCount = 0; // 重连次数

    public MyWsClient(URI serverUri, Map<String, String> httpHeaders, String key) {
        super(serverUri, new Draft_6455(), httpHeaders);
        this.key = key;
        this.channelGroup = ChatWebsocketServer.CHANNEL_MAP.get(key);
    }

    public Thread getHeartBeatThread() {
        return this.heartBeatThread;
    }

    /**
     * 关闭老心跳线程，并重新开启新的心跳线程
     */
    public void setHeartBeatThread(Thread thread) {
        if (heartBeatThread != null && heartBeatThread.isAlive()) heartBeatThread.interrupt();
        this.heartBeatThread = thread;
        if (this.heartBeatThread == null) return;
        this.heartBeatThread.start();
        this.reCount = 0;
    }

    public ChannelGroup getChannelGroup() {
        return this.channelGroup;
    }

    /**
     * 向已连接的弹幕客户端发送解析好的弹幕消息
     * 若客户端不存在则关闭该弹幕服务监听器
     */
    public void sendMsg(String message) {
        if (getChannelGroup() != null && getChannelGroup().size() > 0)
            getChannelGroup().writeAndFlush(message);
        else this.close();
    }

    @Override
    public void onMessage(String s) {
    }

    @Override
    public void onClose(int i, String s, boolean b) {
        log.warn("【{}】，断开连接", key);
        disconnect();
    }

    @Override
    public void onError(Exception e) {
        log.error(String.format("【%s】，连接异常", key), e);
        disconnect();
    }

    /**
     * 弹幕监听器发生关闭时，二次检查是否确认关闭
     * 若需重新启动，则尝试至多4次重连行为
     */
    private void disconnect() {
        new Thread(() -> {
            synchronized (this) {
                if (this.isOpen()) return;
                // 停止心跳线程
                if (heartBeatThread != null && heartBeatThread.isAlive()) heartBeatThread.interrupt();
                // 无客户端连接或重连次数未清零，不进行重连尝试
                if (channelGroup == null || channelGroup.size() == 0 || reCount > 4) return;
                // 与当前弹幕监听器不匹配
                if (!this.equals(ChatWebsocketServer.WS_MAP.get(key))) return;
                try { // 尝试重连平台弹幕服务
                    while (reCount++ <= 4 && !this.isOpen())
                        if (this.reconnectBlocking()) return;
                } catch (Exception e) {
                    log.error(String.format("【%s】，重连失败", key), e);
                }
                // 重连失败。关闭所有连接客户端
                if (channelGroup.size() > 0) channelGroup.close();
            }
        }).start();
    }
}
